package com.springcloud.tread.controller;


import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.springcloud.tread.pojo.AnnualProfit;
import com.springcloud.tread.pojo.IndexData;
import com.springcloud.tread.pojo.Tread;
import com.springcloud.tread.pojo.profit;
import com.springcloud.tread.service.IndexDataClientService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;


import java.util.*;

@RestController
public class IndexDataController {

    @Autowired
    IndexDataClientService indexDataClientService;

    @GetMapping("/customer/get/{id}/{ma}/{buyThreshold}/{sellThreshold}/{serviceCharge}/{startDate}/{endDate}")
//    @CrossOrigin//支持跨域请求，因为请求使用的是一个端口，而资源又是另外一个端口
    public Map<String, Object> get(@PathVariable("id") String id, @PathVariable("ma") int ma, @PathVariable("buyThreshold") float buyThreshold, @PathVariable("sellThreshold") float sellThreshold, @PathVariable("serviceCharge") float serviceCharge, @PathVariable("startDate") String startDate, @PathVariable("endDate") String endDate) {
        System.out.println(ma);
        List<IndexData> indexDatas = indexDataClientService.getIndexData(id);
        Collections.reverse(indexDatas);
        //返回最开始的时间和最晚的时间
        String indexStartDate = indexDatas.get(0).getDate();
        String indexEndDate = indexDatas.get(indexDatas.size() - 1).getDate();
        //得出对应的日期指数数据
        indexDatas = getStartDateAndEndDate(indexDatas, startDate, endDate);
//        int ma = 20;
        float sellRate = sellThreshold;
        float buyRate = buyThreshold;
//        float serviceCharge = serviceCharge;
        Map<String, Object> res = getProfits(ma, sellRate, buyRate, serviceCharge, indexDatas);

        //计算指数收益和趋势投资收益，以及他们的年化收益
        //指数收益率
        float eclosepoint = indexDatas.get(indexDatas.size() - 1).getClosePoint();
        float sclosepoint = indexDatas.get(0).getClosePoint();
        float indexIncomeTotal = (eclosepoint - sclosepoint) / sclosepoint;

        //趋势投资收益率
        List<profit> profits = (List<profit>) res.get("profits");
        float sprofitvalue = profits.get(0).getValue();
        float eprofitvalue = profits.get(profits.size() - 1).getValue();
        float trendIncomeTotal = (sclosepoint / eclosepoint) / sprofitvalue;

        //指数年化收益率
        //获取年,这里不能用整形，会导致除数为0
        float years = getYear(indexDatas);
        float indexIncomeAnnual = (float) Math.pow(1 + indexIncomeTotal, 1 / years) - 1;
        System.out.println(indexIncomeAnnual);
        //趋势投资年化收益率
        float trendIncomeAnnual = (float) Math.pow(1 + trendIncomeTotal, 1 / years) - 1;
        System.out.println(trendIncomeAnnual);


        //统计交易记录
        float winCount = (float) res.get("winCount");
        System.out.println(winCount);
        float totalWinRate = (float) res.get("totalWinRate");
        System.out.println(totalWinRate);
        float avgWinRate = (float) res.get("avgWinRate");
        System.out.println(avgWinRate);
        float totalLossRate = (float) res.get("totalLossRate");
        System.out.println(totalLossRate);
        float lossCount = (float) res.get("lossCount");
        System.out.println(lossCount);
        float avgLossRate = (float) res.get("avgLossRate");
        System.out.println(avgLossRate);

        //收益分布对比

        Map<String, Object> map = getAllYearProfit(indexDatas, profits);
        List<AnnualProfit> annualProfits = (List<AnnualProfit>) map.get("annualProfits");


        Map<String, Object> maps = new HashMap<>();
        maps.put("indexDatas", indexDatas);
        maps.put("indexStartDate", indexStartDate);
        maps.put("indexEndDate", indexEndDate);
        maps.put("profits", res.get("profits"));
        maps.put("treads", res.get("treads"));
        maps.put("indexIncomeTotal", indexIncomeTotal);
        maps.put("indexIncomeAnnual", indexIncomeAnnual);
        maps.put("trendIncomeTotal", trendIncomeTotal);
        maps.put("trendIncomeAnnual", trendIncomeAnnual);
        maps.put("years", years);
        maps.put("winCount", winCount);
        maps.put("totalWinRate", totalWinRate);
        maps.put("avgWinRate", avgWinRate);
        maps.put("totalLossRate", totalLossRate);
        maps.put("lossCount", lossCount);
        maps.put("avgLossRate", avgLossRate);
        maps.put("annualProfits", annualProfits);
        return maps;
    }

    private List<IndexData> getStartDateAndEndDate(List<IndexData> indexDatas, String startDate, String endDate) {
        if (StrUtil.isBlankOrUndefined(startDate) || StrUtil.isBlankOrUndefined(endDate))
            return indexDatas;
        Date start = DateUtil.parse(startDate);
        Date end = DateUtil.parse(endDate);
        List<IndexData> res = new ArrayList<>();
        for (IndexData indexData : indexDatas) {
            Date now = DateUtil.parse(indexData.getDate());
            if (now.getTime() >= start.getTime() && now.getTime() <= end.getTime()) res.add(indexData);
        }
        return res;
    }
    /**
     * 定投
     *  便利每天的收盘价
     *  一到7天就买入1000
     *  累计现金
     *
     *  当小于卖出阈值则卖出
     *  大于买入阈值则买入
     *
     */

    /**
     * ma:均线值
     * sellRate:卖出域
     * buyRate:买入域
     * serviceCharge
     */


    public Map<String, Object> getProfits(int ma, float sellRate, float buyRate, float serviceCharge, List<IndexData> indexDatas) {
        float share = 0;
        float value = 0;
        float initCash = 1000;
        float cash = initCash;
        float init = 0;
        float winCount = 0;
        float totalWinRate = 0;
        float avgWinRate = 0;
        float totalLossRate = 0;
        float lossCount = 0;
        float avgLossRate = 0;
        int count = 0;//定投
        if (!indexDatas.isEmpty())
            init = indexDatas.get(0).getClosePoint();

        //记录每天的获利数据
        List<profit> profits = new ArrayList<>();
        //记录获利，交易集合
        Map<String, Object> res = new HashMap<>();
        //记录交易
        List<Tread> treads = new ArrayList<>();
        for (int i = 0; i < indexDatas.size(); i++) {
//            //定投
//            count++;
//            if (count % 7 == 0) {
//                cash += 1000;
//                count = 0;
//            }
            float closePoint = indexDatas.get(i).getClosePoint();
            float avg = getAvg(i, ma, indexDatas);
            float max = getMax(i, ma, indexDatas);
            float incrRate = avg / closePoint;
            float decrRate = max / closePoint;

            if (avg != 0) {
                //超过盈利域购买
                if (incrRate > buyRate) {
                    if (share == 0) {
                        share = cash / closePoint;
                        cash = 0;

//买入
                        Tread trade = new Tread();
                        trade.setBuyDate(indexDatas.get(i).getDate());
                        trade.setBuyClosePoint(indexDatas.get(i).getClosePoint());
                        trade.setSellDate("n/a");
                        trade.setSellClosePoint(0);
                        treads.add(trade);

                    }

                }
                //低于sell域抛出
                else if (decrRate < sellRate) {
                    if (share != 0) {
                        cash = closePoint * share * (1 - serviceCharge);
                        share = 0;

                        //一买一卖出才是一个完整的交易
                        Tread tread = treads.get(treads.size() - 1);
                        tread.setSellClosePoint(indexDatas.get(i).getClosePoint());
                        tread.setSellDate(indexDatas.get(i).getDate());
                        tread.setRate(cash / initCash);

                        //交易信息统计
                        if (tread.getSellClosePoint() - tread.getBuyClosePoint() > 0) {
                            totalWinRate += (tread.getSellClosePoint() - tread.getBuyClosePoint()) / tread.getBuyClosePoint();
                            winCount++;
                        } else {
                            totalLossRate += (tread.getSellClosePoint() - tread.getBuyClosePoint()) / tread.getBuyClosePoint();
                            lossCount++;
                        }
                    }
                } else {

                }
            }

            if (share != 0) {
                value = closePoint * share;
            } else {
                value = cash;
            }
            //计算利率
            float rate = value / initCash;
            profit profit = new profit();
            profit.setDate(indexDatas.get(i).getDate());
            profit.setValue(rate * init);
            profits.add(profit);
        }
        avgWinRate = totalWinRate / winCount;
        avgLossRate = totalLossRate / lossCount;

        res.put("winCount", winCount);
        res.put("totalWinRate", totalWinRate);
        res.put("avgWinRate", avgWinRate);
        res.put("totalLossRate", totalLossRate);
        res.put("lossCount", lossCount);
        res.put("avgLossRate", avgLossRate);
        res.put("profits", profits);
        res.put("treads", treads);
        return res;
    }

    private float getMax(int i, int ma, List<IndexData> indexDatas) {
        int start = i - ma - 1;
        if (start < 0) return 0;
        float max = 0;
        for (int j = start; j < i - 1; j++) {
            float closePoint = indexDatas.get(j).getClosePoint();
            max = Math.max(closePoint, max);
        }
        return max;
    }

    private float getAvg(int i, int ma, List<IndexData> indexDatas) {
        int start = i - ma - 1;
        if (start < 0) return 0;
        float sum = 0;
        for (int j = start; j < i - 1; j++) {
            float closePoint = indexDatas.get(j).getClosePoint();
            sum += closePoint;
        }
        return sum / (i - 1 - start);
    }

    private float getYear(List<IndexData> indexData) {
        String start = indexData.get(0).getDate();
        String end = indexData.get(indexData.size() - 1).getDate();
        Date sdate = DateUtil.parse(start);
        Date edate = DateUtil.parse(end);
        float days = DateUtil.between(sdate, edate, DateUnit.DAY);
        float year = days / 365f;
        return year;
    }


    //获取指数全范围的年收益
    private Map<String, Object> getAllYearProfit(List<IndexData> indexDatas, List<profit> profits) {
        Map<String, Object> map = new HashMap<>();
        List<AnnualProfit> annualProfits = new ArrayList<>();
        String start = indexDatas.get(0).getDate();
        String end = indexDatas.get(indexDatas.size() - 1).getDate();
        int syear = getDateYear(start);
        int eyear = getDateYear(end);
        for (int year = syear; year <= eyear; year++) {
            float indexIncome = getIndexDataIncomeProfit(year, indexDatas);
            float trendIncome = getTreadIncomeProfit(year, profits);
            AnnualProfit annualProfit = new AnnualProfit();
            annualProfit.setYear(year);
            annualProfit.setIndexIncomeProfit(indexIncome);
            annualProfit.setTreadIncomeProfit(trendIncome);
            annualProfits.add(annualProfit);
        }
        map.put("annualProfits", annualProfits);
        return map;
    }

    //获取指数年化收益
    private float getIndexDataIncomeProfit(int year, List<IndexData> indexDatas) {
        IndexData frist = null;
        IndexData last = null;
        for (IndexData indexData : indexDatas) {
            String date = indexData.getDate();
            if (getDateYear(date) == year) {
                if (frist == null) frist = indexData;
                last = indexData;
            }
        }
        float yearClosePoint = (last.getClosePoint() - frist.getClosePoint()) / frist.getClosePoint();
        return yearClosePoint;
    }


    //获取趋势全范围的年收益

    //获取趋势投资收益
    private float getTreadIncomeProfit(int year, List<profit> profits) {
        profit frist = null;
        profit last = null;
        for (profit profit : profits) {
            String date = profit.getDate();
            if (getDateYear(date) == year) {
                if (frist == null) frist = profit;
                last = profit;
            }
        }
        float yearprofit = (last.getValue() - frist.getValue()) / frist.getValue();
        return yearprofit;
    }

    //获取日期里面的年
    private int getDateYear(String date) {
        String strYear = StrUtil.subBefore(date, "-", false);
        return Convert.toInt(strYear);
    }
}
